package com.swak.generate.codegen;

import java.io.File;
import java.util.List;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swak.Constants;
import com.swak.OS;
import com.swak.generate.codegen.dialects.DatabaseOperater;
import com.swak.template.FreeMarkerConfigurer;
import com.swak.template.TemplateMarker;
import com.swak.utils.IOUtils;
import com.swak.utils.StringUtils;

public class CodeGenerator {

	private static Logger logger = LoggerFactory.getLogger(CodeGenerator.class);

	private String url;
	private String userName;
	private String passWord;
	private String packageName;
	private String generateDir;
	private String generateModule;
	private boolean generateAll = true;
	private boolean fluxDrive = true;
	private boolean useMerge = true; // 是否是统计表
	private String initScript;

	public CodeGenerator(String url, String userName, String passWord, String packageName, String generateDir) {
		this(url, userName, passWord, packageName, generateDir, StringUtils.EMPTY, true, true, false, null);
	}

	public CodeGenerator(String url, String userName, String passWord, String packageName, String generateDir,
			String initScript) {
		this(url, userName, passWord, packageName, generateDir, StringUtils.EMPTY, true, true, false, initScript);
	}

	public CodeGenerator(String url, String userName, String passWord, String packageName, String generateDir,
			boolean useMerge, String initScript) {
		this(url, userName, passWord, packageName, generateDir, StringUtils.EMPTY, true, true, useMerge, initScript);
	}

	public CodeGenerator(String url, String userName, String passWord, String packageName, String generateDir,
			String generateModule, boolean generateAll, boolean fluxDrive, boolean useMerge, String initScript) {
		this.url = url;
		this.userName = userName;
		this.passWord = passWord;
		this.packageName = packageName;
		this.generateDir = generateDir;
		this.generateModule = generateModule;
		this.generateAll = generateAll;
		this.fluxDrive = fluxDrive;
		this.useMerge = useMerge;
		this.initScript = initScript;
	}

	public void execute() {

		// 初始化freemaker模板
		this.initTemplateMarker();

		// 初始化源码目录
		File outDir = this.initSourceDirectory();

		// 创建数据库操作
		DatabaseOperater dbOperater = DatabaseOperater.newDatabaseOperater(url, userName, passWord);

		// 使用脚本初始化数据库
		this.initDBUseScript(dbOperater);

		// 所有的数据表
		try {
			List<String> tables = dbOperater.getTables();
			logInfo("代码生成数量：" + tables.size());
			logInfo("代码生成包名：" + this.packageName);
			logInfo("代码生成目录：" + outDir.getAbsolutePath());
			logInfo("代码生成内容：" + (generateAll ? "Entity、Dto、Mapper、Service、Impls" : "Entity、Dto"));
			int i = 1;
			for (String utable : tables) {
				Table table = dbOperater.getTable(utable);
				Scheme scheme = new Scheme(packageName, table, generateAll, fluxDrive, useMerge);
				if (!(StringUtils.isBlank(generateModule)
						|| StringUtils.equals(generateModule, scheme.getModuleName()))) {
					continue;
				}
				List<String> files = GenUtils.genCode(outDir, scheme);
				logInfo("第" + (i++) + "个表  " + utable + " 转换代码成功！文件列表:" + files);
			}
		} catch (Exception e) {
			logError("Generate Code Error:", e);
		} finally {
			IOUtils.closeQuietly(dbOperater);
		}
	}

	private void initDBUseScript(DatabaseOperater dbOperater) {
		if (StringUtils.isBlank(this.initScript)) {
			return;
		}

		// 需要指定的 sql
		String[] sqls = StringUtils.split(this.initScript, ";");
		for (String sql : sqls) {
			boolean success = true;
			try {
				dbOperater.execSql(sql);
			} catch (Exception e) {
				e.printStackTrace();
				success = false;
			}
			logger.debug(
					StringUtils.format("[%s] - 执行SQL:%s", success ? "成功" : "失败", StringUtils.replace(sql, "\n", "")));
		}
	}

	private File initSourceDirectory() {
		File generateDirFile = new File(OS.home(), "/Desktop");
		if (StringUtils.isNotBlank(generateDir)) {
			generateDirFile = new File(generateDir);
		}
		return generateDirFile;
	}

	private void initTemplateMarker() {
		FreeMarkerConfigurer factory = new FreeMarkerConfigurer();
		factory.setDefaultEncoding(Constants.DEFAULT_ENCODING.name());
		Properties settings = getDefaultProperties();
		factory.setFreemarkerSettings(settings);
		new TemplateMarker(factory.getConfiguration());
	}

	private Properties getDefaultProperties() {
		Properties settings = new Properties();
		settings.put("defaultEncoding", Constants.DEFAULT_ENCODING.name());
		settings.put("url_escaping_charset", Constants.DEFAULT_ENCODING.name());
		settings.put("locale", "zh_CN");
		settings.put("template_update_delay", "0");
		settings.put("tag_syntax", "auto_detect");
		settings.put("whitespace_stripping", "true");
		settings.put("classic_compatible", "true");
		settings.put("number_format", "0");
		settings.put("boolean_format", "true,false");
		settings.put("datetime_format", "yyyy-MM-dd HH:mm:ss");
		settings.put("date_format", "yyyy-MM-dd");
		settings.put("time_format", "HH:mm:ss");
		settings.put("object_wrapper", "freemarker.ext.beans.BeansWrapper");
		return settings;
	}

	protected void logInfo(String message) {
		logger.info(message);
	}

	protected void logError(String message, Exception e) {
		logger.error(message, e);
	}
}
